﻿#include "pch.h"
#include "region.h"
#include "engine/renderd2d.h"
#include <common/winapi.h>
#include <common/Exception.h>

namespace JOUI
{
	UIRegion::UIRegion()
	{
		return_if_true(m_geometry, L"已经创建了区域");
		//确定几何形边界矩形
		D2D1_RECT_F rc = D2D1::InfiniteRect();

		//创建几何形
		ID2D1RectangleGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreateRectangleGeometry(rc, &geometry),
			L"区域几何形创建失败"
		);

		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	UIRegion::~UIRegion()
	{
		if (m_geometry)
			m_geometry->Release();
	}
	UIRegion::UIRegion(FLOAT left, FLOAT top, FLOAT right, FLOAT bottom)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		_offset_(false, left, top, right, bottom);
		D2D1_RECT_F rect = { left, top, right, bottom };
		m_size = { left, top, right, bottom };
		ID2D1RectangleGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreateRectangleGeometry(&rect, (ID2D1RectangleGeometry**)&geometry), L"区域几何形创建失败"
		);

		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	UIRegion::UIRegion(FLOAT left, FLOAT top, FLOAT right, FLOAT bottom, BOOL is_clip)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		//确定椭圆边界
		_offset_(false, left, top, right, bottom);
		ExRectF rc = ExRectF(left, top, right, bottom).Normalize();
		m_size = { left, top, right, bottom };
		//创建椭圆几何形
		ID2D1EllipseGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreateEllipseGeometry(
				D2D1::Ellipse(
					D2D1::Point2F(rc.GetHorzCenter(), rc.GetVertCenter()),
					rc.Width() / 2, rc.Height() / 2
				), &geometry
			), L"区域几何形创建失败"
		);
		m_is_clip = is_clip;
		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	UIRegion::UIRegion(FLOAT left, FLOAT top, FLOAT right, FLOAT bottom, FLOAT radius_left_top, FLOAT radius_right_top, FLOAT radius_right_bottom, FLOAT radius_left_bottom)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		//创建路径几何形
		ID2D1PathGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreatePathGeometry(&geometry),
			L"区域几何形创建失败"
		);
		m_size = { left, top, right, bottom };
		//开始描述
		ID2D1GeometrySink* sink;
		throw_if_failed(geometry->Open(&sink), L"获取路径描述器失败");

		//生成圆角矩形
		UIPath::MakeRoundRectFigure(sink, left, top, right, bottom,
			radius_left_top, radius_right_top,
			radius_right_bottom, radius_left_bottom, 0
		);
		//结束描述
		throw_if_failed(sink->Close(), L"关闭路径描述器失败");
		sink->Release();

		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	UIRegion::UIRegion(FLOAT left, FLOAT top, FLOAT right, FLOAT bottom, FLOAT radiusX, FLOAT radiusY, BOOL is_clip)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		ID2D1RectangleGeometry* geometry = nullptr;
		if (radiusX == 0 && radiusY == 0)
		{
			D2D1_RECT_F rect = { left, top, right, bottom };
			g_d2d_factory->CreateRectangleGeometry(&rect, (ID2D1RectangleGeometry**)&geometry);
			throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
			geometry->Release();
		}
		else
		{
			D2D1_ROUNDED_RECT rrect = { 0 };
			rrect.rect = { left, top, right, bottom };
			rrect.radiusX = radiusX;
			rrect.radiusY = radiusY;
			g_d2d_factory->CreateRoundedRectangleGeometry(&rrect, (ID2D1RoundedRectangleGeometry**)&geometry);
			throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
			geometry->Release();
		}
	}
	UIRegion::UIRegion(UIPath* hPath, const ExMatrix* tranform)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		D2D1_MATRIX_3X2_F matrix = MatrixEx(tranform);

		//生成变换几何形
		ID2D1TransformedGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreateTransformedGeometry(
				(ID2D1PathGeometry*)hPath->GetContext(0),
				&matrix, &geometry
			), L"区域几何形创建失败"
		);

		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	UIRegion::UIRegion(UIRegion* region, const ExMatrix* tranform)
	{
		return_if_true(m_geometry, L"已经创建了区域");
		D2D1_MATRIX_3X2_F matrix = MatrixEx(tranform);

		ID2D1TransformedGeometry* geometry;
		throw_if_failed(
			g_d2d_factory->CreateTransformedGeometry(
				(ID2D1PathGeometry*)region->GetContext(),
				&matrix, &geometry
			), L"区域几何形创建失败"
		);

		throw_if_failed(geometry->QueryInterface(&m_geometry), L"查询接口失败");
		geometry->Release();
	}
	HRESULT UIRegion::CombineWithRect(float left, float top, float right, float bottom,
		RegionCombineMode mode, const ExMatrix* tranform)
	{
		//确定矩形边界
		_offset_(left, top, right, bottom);
		D2D1_RECT_F rc = D2D1Rect(left, top, right, bottom);

		try
		{
			//创建矩形几何形
			ID2D1RectangleGeometry* geometry;
			throw_if_failed(
				g_d2d_factory->CreateRectangleGeometry(rc, &geometry),
				L"源区域几何形创建失败"
			);

			//合并并覆盖当前几何形
			ID2D1Geometry* new_geometry = Combine(m_geometry, geometry, mode, tranform);
			m_geometry->Release();
			m_geometry = new_geometry;
			geometry->Release();
			return S_OK;
		}catch_default({});
	}
	HRESULT UIRegion::CombineWithPath(UIPath *path, RegionCombineMode mode, const ExMatrix* tranform)
	{
		CHECK_PARAM(path);

		try
		{
			//合并并覆盖当前几何形
			ID2D1Geometry* new_geometry = Combine(m_geometry, (ID2D1PathGeometry*)path->GetContext(0), mode, tranform);
			m_geometry->Release();
			m_geometry = new_geometry;
			return S_OK;
		}
		catch_default({});
	}
	HRESULT UIRegion::CombineWithRegion(UIRegion *region, RegionCombineMode mode, const ExMatrix* tranform)
	{
		CHECK_PARAM(region);

		try
		{
			ID2D1Geometry* new_geometry = Combine(m_geometry, (ID2D1Geometry*)region->GetContext(), mode, tranform);
			m_geometry->Release();
			m_geometry = new_geometry;

			return S_OK;
		}
		catch_default({});
	}
	HRESULT UIRegion::HitTest(float x, float y) const
	{
		//偏移坐标
		_offset_(false, x, y);

		//命中测试
		BOOL hit = FALSE;
		handle_if_failed(
			m_geometry->FillContainsPoint(D2D1::Point2F(x, y), nullptr, &hit),
			L"检测点是否在区域内失败"
		);

		return hit ? S_OK : S_FALSE;
	}
	HRESULT UIRegion::GetBounds(ExRectF* r_bounds_rect) const
	{
		CHECK_PARAM(r_bounds_rect);

		//获取边界
		D2D1_RECT_F rc;
		handle_if_failed(m_geometry->GetBounds(D2D1::Matrix3x2F::Identity(), &rc), L"获取边界矩形失败");
		
		//偏移回去并返回
		_offset_(true, rc);
		*r_bounds_rect = ExRectF(rc.left, rc.top, rc.right, rc.bottom);
		return S_OK;
	}

	LPVOID UIRegion::GetContext() const
	{
		return m_geometry;
	}

	ID2D1Geometry* UIRegion::Combine(ID2D1Geometry* geometry1, ID2D1Geometry* geometry2,
		RegionCombineMode mode, const ExMatrix* tranform_matrix)
	{
		//获取合并模式
		D2D1_COMBINE_MODE combine_mode{};
		switch (mode)
		{
		case RegionCombineMode::Copy: break;
		case RegionCombineMode::Union: combine_mode = D2D1_COMBINE_MODE_UNION; break;
		case RegionCombineMode::Intersect: combine_mode = D2D1_COMBINE_MODE_INTERSECT; break;
		case RegionCombineMode::Exclude: combine_mode = D2D1_COMBINE_MODE_EXCLUDE; break;
		case RegionCombineMode::Xor: combine_mode = D2D1_COMBINE_MODE_XOR; break;
		default: throw_ex(E_NOTIMPL, L"不支持该合并模式");
		}

		//获取变换矩阵
		D2D1_MATRIX_3X2_F matrix = MatrixEx(tranform_matrix);

		//拷贝则直接替换
		if (mode == RegionCombineMode::Copy)
		{
			//则创建一个变换后的几何形
			ID2D1TransformedGeometry* new_geometry;
			throw_if_failed(
				g_d2d_factory->CreateTransformedGeometry(
					geometry1, matrix, &new_geometry
				), L"创建新几何形对象失败"
			);

			//将新几何形直接返回
			return new_geometry;
		}
		else
		{
			ID2D1PathGeometry* new_geometry;
			//创建目标几何形
			throw_if_failed(
				g_d2d_factory->CreatePathGeometry(&new_geometry),
				L"创建新几何形对象失败"
			);

			//开始描述几何形
			ID2D1GeometrySink* sink;
			throw_if_failed(new_geometry->Open(&sink), L"开始描述几何形失败");

			//合并
			throw_if_failed(
				geometry1->CombineWithGeometry(geometry2, combine_mode,
					matrix, sink),
				L"合并几何形失败"
			);

			//扫尾
			throw_if_failed(sink->Close(), L"描述几何形对象错误");
			sink->Release();

			//将新几何形直接返回
			return new_geometry;
		}
	}
}


